package pokeronlab_2014.mcts;
import java.io.PrintStream;
import java.util.Random;
import java.util.prefs.InvalidPreferencesFormatException;

import pokeronlab_2014.ConfigManager;
import pokeronlab_2014.Controller;
import pokeronlab_2014.OpponentModeller;
import pokeronlab_2014.SVMClassifierData;

import com.biotools.meerkat.Deck;
import com.biotools.meerkat.GameInfo;
//import java.util.LinkedList;
//import java.util.List;
//import java.util.Locale.Category;
//import java.util.logging.Level;

public abstract class TreeNode {
	/**
	 * A csúcsok gyerekeinek a száma, ha nem leosztanak egy lapot
	 */
	static int nActions = 3;
	/**
	 * A csúcsok gyerekeinek a száma, ha leosztanak egy lapot
	 */
	static int nCard = 52;
	/**
	 * a képletbe a súlyozásért felelős
	 */
	static double c ;
	
	static double hatvany;
	
	
	/**
	 * azt határozza meg hogy a csúcsból cselekvéssel vagy új kárty eseménnyel megyünk egy szintel lejebb
	 */
	NodeType typeOfNode;
	/**
	 * 0=preflop, 1=flop, 2=turn, 3=river
	 */
	int	round;
	MCTSDecision MCTS;
	
	
	TreeNode[] children;
	public TreeNode parent;
	public double nVisits, totValue;
	public SVMClassifierData SVMbemenet;
	
	public int jatekID = 1;
	public int [] inpot = new int[10];
	public int nextplayer;

	/**
	 * azt adja meg milyen idexű a szülője gyerek tömbjében, ha szülő player volt akkor 0=fold, 1=call/check, 2=raise
	 * új kártya esetén 0-51 egy szám mely egyértelműen helyettesíthető egy lappal
	 */
	public int childrenNumber;
	public Deck deck = new Deck();
	public int playerID;
	public GameRules rules = new GameRules();
	
	public OpponentModeller OP;
	public int mypos;
	public GameInfo o;
	public int level;

	enum NodeType {
		playeraction_my, playeraction_other, newcard
	}

	public TreeNode() {
			
		round =1;
		parent = null;
		SVMbemenet = new SVMClassifierData();
		level =0;
		nVisits = 0;
		totValue = 0;
		o = Controller.thisGameInfo;
	}

	/**
	 * @param parent
	 * @param childrenNumber
	 *  ez mondja meg h milyen cselekvéssel mentünk a csúcsba cselekvés esetén: 0-2, új lap esetén a lehetséges új lapok száma  
	 * @param playerID
	 * @param bet 
	 * amennyit rá emel. pl: sb 1, bb 2, utg 4, és emel 4-el akkor ez a szám 4
	 */
	public void creatNode(TreeNode parent, int childrenNumber, int playerID, double bet, int level) {
		this.parent =  parent;
		this.childrenNumber = childrenNumber;
		jatekID = parent.jatekID;
		SVMbemenet = parent.SVMbemenet.clone();
		this.playerID = playerID;
		this.inpot = parent.inpot;
		rules = parent.rules.clone(childrenNumber);
		this.level = level+1;
		String tmp2;
		if(playerID==-1)
			tmp2 = "új közös lap csúcs";
		else
			tmp2 = ""+ playerID;
		
		String tmp = "TreeNode.creatNode playerID= " + tmp2 + ", bet= " + bet + ", childrenNumber= " + childrenNumber + ", level= " + this.level;
		//Controller.debugWindow.printMessage(tmp);
		
		

		
		int maxbet=0;
		for(int i=0;i<10;i++){
			if(inpot[i]>maxbet)
				maxbet=inpot[i];
		}
		boolean nextround= true;
		//-1 azt jelenti, getPlayerSeat nem találta a játékost az asztalnál, mivel a playerID rossz
		if(playerID!=-1)
		{
			int seat =rules.getplayerSeatFromID(playerID);
			int i =seat;
			while(nextround== true && i-seat<10){
				i++;
				if(inpot[i%10]<maxbet && SVMbemenet.ingame(i%10)){
					nextplayer = SVMbemenet.playerIDs[i%10];
					nextround= false;
				}
			}
		}
		else
			nextround= false;
		//ha igaz következő kör jön
		if(nextround)
			round++;
		
		
		
//		for (int j = seat; j < 10+seat; j++)
//			//az apiban nincs benne ez a fv már, de szerintem itt nem is kell
//			//pont ezért
//			//if (Controller.thisGameInfo.activePlayer(i))
//				if (Controller.thisGameInfo.getAmountToCall(j%10) != 0)
//					nodeType = NodeType.playeraction_other;
//		if (nodeType == NodeType.playeraction_other
//				//.advanceCurrentPlayer() cserélve .getCurrentPlayerSeat()
//				//-re, ellenőrizd hogy jó-e!
//				&& Controller.thisGameInfo.getCurrentPlayerSeat() == mypos)
//			nodeType = NodeType.playeraction_other;

		
		// playerID -1 az azt jelenti hogy új lap érkezett
		if(round<4 && parent.playerID != -1)
			SVMbemenet.setPlayerData(round, rules.getplayerSeatFromID(parent.playerID), this.childrenNumber);
		
		
		//foldolt az ellenfél
		if(childrenNumber==0)
			rules.setPlayerInGame(parent.rules.actualplayer);
//		if(childrenNumber==3 && parent.nodeType!=NodeType.newcard)
//			if(rules.round<2)
//				rules.setmaxcall(rules.fixlimit);
//			else		
//				rules.setmaxcall(rules.fixlimit*2);
		
		if(parent.typeOfNode==NodeType.newcard){
			if(round==2)
				rules.turn= childrenNumber-100;
			if(round==3)
				rules.river= childrenNumber-100;
		}


		// logger = Logger.getLogger(this.getClass().getName());
		// logger.log(Level.INFO,
		// String.format("Player" + " %s added to database.", name));
		
		rules.setmaxcall(bet);
		if(playerID!=-1){
				rules.setinpot(bet, rules.getplayerSeatFromID(playerID));
		}
		else
			rules.newRound();
		
	}

	

	public abstract TreeNode select(TreeNode currentNode);
	
	public abstract TreeNode simulate(TreeNode currentNode);
	
	public abstract void expand(TreeNode currentNode); 
	
	public abstract TreeNode selectNoFold(TreeNode currentNode);

	/**
	 * @return A visszatérési érték igaz, ha nincs gyereke
	 */
	public boolean isLeaf() {

		return children == null;
	}
	
	public boolean isOver(TreeNode currentNode){
	
		if(rules.playeringame[mypos]==0)
			return true;
		
		
		int numberOfInGame =0;
		for(int i=0;i<10;i++)
			if(rules.playeringame[i]==1)
				numberOfInGame++;
		
		String tmp = "numberOfInGame=" + numberOfInGame;
		//Controller.debugWindow.printMessage(tmp);;
		if(currentNode.round==4 && currentNode.typeOfNode==NodeType.newcard)
			return true;
		
		
		if(numberOfInGame<2 )//&& !SVMbemenet.allin())
			return true;
//		if(SVMbemenet.allin() && numberOfInGame==0)
//			return true;
		return false;
		
	}
	
	/**
	 * @return 1= a bot biztosan nyert 2= a bot biztosan veszített 3= nem tudni ki nyert 
	 */
	public int isAmIWinner(){
		if(rules.playeringame[mypos]==0)
			return 2;
		
		int numberOfInGame =0;
		for(int i=0;i<10;i++)
			if(rules.playeringame[i]==1)
				numberOfInGame++;
		
		if(numberOfInGame<2 )//&& !SVMbemenet.allin())
			return 1;
		
		return 3;
	}	
	
	public TreeNode decision(TreeNode currentNode){
		
		double children0tmp = currentNode.children[0].totValue/currentNode.children[0].nVisits;
		double children1tmp = currentNode.children[1].totValue/currentNode.children[1].nVisits;
		double children2tmp = currentNode.children[2].totValue/currentNode.children[2].nVisits;
		double children0;
		double children1;
		double random = Math.random();
		
		
		children0tmp = Math.pow(children0tmp,hatvany);
		children1tmp = Math.pow(children1tmp,hatvany);
		children2tmp = Math.pow(children2tmp,hatvany);
		
		
		PrintStream out = System.out;
		out.println("childre0= " + children0tmp + ", childre1= " + children1tmp + ", childre2= " + children2tmp);
		
		
		if(Controller.thisGameInfo.getAmountToCall(currentNode.playerID)==0){
			children1=children1tmp/(children1tmp+children2tmp);

			if (random < children1)
				currentNode = currentNode.children[1];
			else 
				currentNode = currentNode.children[2];
		}
		else{
			children0=children0tmp/(children0tmp+children1tmp+children2tmp);
			children1=children1tmp/(children0tmp+children1tmp+children2tmp);

			if (random < children0)
				currentNode = currentNode.children[0];
			else {
				if (random < children0 + children1)
					currentNode = currentNode.children[1];
				else {
					if(rules.maxbet==0)
						currentNode = currentNode.children[1];
					else
						currentNode = currentNode.children[2];
				}
			}
		}
		
		return currentNode;
		
	}

	public void setc(int newc){
		c=newc;
	}
	
	public void sethatvany(double newhatvany){
		

		hatvany=newhatvany;
	}
}
